package com.basker.pisces.orm.session;

import java.lang.reflect.Array;
import java.util.Collection;
import java.util.List;

import com.basker.pisces.core.DataContractGenerator;
import com.basker.pisces.core.IInitialize;
import com.basker.pisces.core.enums.DataObjectState;
import com.basker.pisces.core.meta.ICollectionField;
import com.basker.pisces.core.meta.IDataObjectMeta;
import com.basker.pisces.exception.ExceptionFactory;
import com.basker.pisces.orm.data.DataRow;
import com.basker.pisces.orm.data.DataSet;
import com.basker.pisces.orm.data.DataTable;
import com.basker.pisces.orm.data.meta.FieldMeta;
import com.basker.pisces.orm.data.meta.TableMeta;

/**
 * 对象映射器，将dataset数据集转换成对象
 *
 * @author hangwen
 */
public class DataMapper {

    public Object[] mapDataObjects(DataSet dataSet, IDataObjectMeta objectMeta) {
        try {
            DataContractGenerator.enable();
            return this.mapDataObjects0(dataSet, objectMeta);
        } finally {
            DataContractGenerator.disable();
        }
    }

    public Object[] mapDataObjects0(DataSet dataSet, IDataObjectMeta objectMeta) {
        // 1.获取objectMeta数据表对应的datatable的数据
        DataTable dataTable = dataSet.getTable(objectMeta.getTableName());
        TableMeta tableMeta = dataTable.getTableMeta();

        // 2.遍历table中的行，每行对应一个数据对象
        int size = dataTable != null ? dataTable.getRows().size() : 0;
        Class<?> dataContractClass = objectMeta.getDataObjectClass();
        Object[] dataObjects = (Object[]) Array.newInstance(dataContractClass, size);

        if (size == 0) {
            return dataObjects;
        }

        for (int i = 0; i < size; i++) {
            // 3.以下都是对于一行记录而言的
            // 3.1 遍历tablemeta中所有的mapFieldMetas，将这些字段的值从row中拿出，赋值给对象
            Object dataObject = objectMeta.createDataObject();
            DataRow dataRow = dataTable.getRows().get(i);

            if (dataObject instanceof IInitialize) {
                ((IInitialize) dataObject).beginInit();
            }

            for (FieldMeta fieldMeta : tableMeta.getMapFieldMetas()) {
                Object value = dataRow.values[fieldMeta.getSelectIndex()];
                boolean isPkField = fieldMeta.getDataField().isPkField();

                if (isPkField) {
                    setPkValue(objectMeta, dataObject, fieldMeta, value);
                } else {
                    fieldMeta.getDataField().setValue(dataObject, value);
                }
            }

            // 3.2 要标记对象的fromdb等字段，这个可以暂不考虑
            objectMeta.setFromDB(dataObject);
            objectMeta.setState(dataObject, DataObjectState.UnChanged);

            dataObjects[i] = dataObject;
        }
        // 4.所有当前表对应映射对象都赋值好后，开始考虑子表，遍历objectMeta的所有集合字段
        // 以下都是对应一个集合字段而言的，单独写在一个函数里
        // 4.1获取集合字段对应的chidlObjectMeta,递归调用mapDataObjects创建子对象集合
        // 4.2 这些子对象的父亲很可能不同，需要分别找到这些子对象的父亲，并添加到父对象对应的集合里
        if (size > 0) {
            for (ICollectionField collectionField : objectMeta.getCollectionFields()) {
                mapCollectionFieldValues(dataObjects, dataTable, dataSet, collectionField);
            }

            for (Object dataObject : dataObjects) {
                if (dataObject instanceof IInitialize) {
                    ((IInitialize) dataObject).endInit();
                }
            }
        }

        return dataObjects;
    }

    @SuppressWarnings("unchecked")
    private void mapCollectionFieldValues(Object[] dataObjects, DataTable dataTable, DataSet dataSet,
                                          ICollectionField collectionField) {
        Object[] objArray = null;
        // 获取当前子表的数据对象
        IDataObjectMeta itemObjectMeta = collectionField.getItemObjectMeta();
        // 对当前集合（当前子表）进行数据对象填充
        objArray = mapDataObjects0(dataSet, itemObjectMeta);

        DataTable collectionTable = dataSet.getTable(itemObjectMeta.getTableName());
        if (collectionTable == null) {
            return;
        }

        List<DataRow> rows = collectionTable.getRows();
        int columnIndex = collectionTable.getTableMeta().getFkFieldMeta().getSelectIndex();
        Object oldfkValue = null;
        Collection<Object> list = null;

        for (int i = 0; i < objArray.length; i++) {
            Object fkValue = rows.get(i).values[columnIndex];
            if (fkValue != oldfkValue) {
                int rowIndex = dataTable.getRowIndexByKeyValue(fkValue);
                Object parentObject = dataObjects[rowIndex];

                list = collectionField.getValue(parentObject);

                oldfkValue = fkValue;
            }

            list.add(objArray[i]);
        }
    }

    private void setPkValue(IDataObjectMeta objectMeta, Object dataObject, FieldMeta fieldMeta, Object value) {
        if (value == null) {
            throw ExceptionFactory.createRuntimeException("pisces-orm.DataMapper.setPkValue-001", "pk value is null!");
        }

        String tableName = fieldMeta.getTableName();
        boolean isSubtable = !tableName.equalsIgnoreCase(objectMeta.getTableName());
        if (isSubtable) {
            // 扩展表存在记录，需要标记fromDB
            String subTableName = tableName;
            objectMeta.setFromDB(dataObject, subTableName);
        } else {
            // 主键主键，赋值
            fieldMeta.getDataField().setValue(dataObject, value);
        }

    }

}
